package wuaipojie

import (
	"context"
	"encoding/xml"
	"fmt"
	"gitee.com/kaylee595/gkaylee/kerr"
	"github.com/PuerkitoBio/goquery"
	"io"
	"net/http"
	url2 "net/url"
	"regexp"
	"strconv"
	"strings"
)

type ReqLogin struct {
	Username           string
	Password           string
	QuestionId         int
	Answer             string
	GRecaptchaResponse string
}

var (
	regexSucceedLocation = regexp.MustCompile(`\$\('succeedlocation'\).innerHTML = '(.*?)'`)
)

func (c *Client) Login(ctx context.Context, r *ReqLogin) error {
	resp := c.httpClient.Get("https://www.52pojie.cn/member.php?mod=logging&action=login").Do(ctx)
	if resp.Err != nil {
		return kerr.WrapTraceStack(resp.Err)
	}
	if resp.StatusCode != http.StatusOK {
		return kerr.WrapTraceStack(NewErrReq(resp, kerr.New("status code must be 200")))
	}
	dom, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return kerr.WrapTraceStack(NewErrReq(resp, err))
	}
	formUrl, formValue, err := func() (*url2.URL, url2.Values, error) {
		formEl := dom.Find("form[name='login']")
		if len(formEl.Nodes) == 0 {
			return nil, nil, kerr.New("login form not found")
		}
		url, ok := formEl.Attr("action") // member.php?mod=logging&amp;action=login&amp;loginsubmit=yes&amp;loginhash=LOaxz
		if !ok {
			return nil, nil, kerr.New("action not found")
		}
		urlS, err := url2.Parse(url)
		if err != nil {
			return nil, nil, kerr.WrapTraceStack(err)
		}
		formHash, ok := formEl.Find("input[name='formhash']").Attr("value") // 47c8c3a9
		if !ok {
			return nil, nil, kerr.New("formhash not found")
		}
		referer, ok := formEl.Find("input[name='referer']").Attr("value") // https://www.52pojie.cn/./
		if !ok {
			return nil, nil, kerr.New("referer not found")
		}
		// updateseccode('cS', '<div class="rfm"><table><tr><th><sec>: </th><td><sec><br /><sec></td></tr></table></div>', 'member::logging');
		script := formEl.Find("script").Text()
		token := "updateseccode("
		script, ok = strings.CutPrefix(script, token)
		if !ok {
			return nil, nil, kerr.WrapTraceStack(fmt.Errorf("script prefix is not %q, got it: %q", token, script))
		}
		token = ", "
		script, _, ok = strings.Cut(script, token)
		if !ok {
			return nil, nil, kerr.WrapTraceStack(fmt.Errorf("script prefix is not %q, got it: %q", token, script))
		}
		if len(script) <= 2 {
			return nil, nil, kerr.WrapTraceStack(fmt.Errorf("script length lte 2, got it: %q", script))
		}
		seccodehash := strings.Clone(script[1 : len(script)-1])
		seccodeverify := seccodehash
		fv := make(url2.Values, 10)
		fv.Set("formhash", formHash)
		fv.Set("referer", referer)
		fv.Set("seccodehash", seccodehash)
		fv.Set("seccodeverify", seccodeverify)
		return urlS, fv, nil
	}()
	if err != nil {
		return kerr.WrapTraceStack(NewErrReq(resp, err))
	}
	formUrl.Scheme = "https"
	formUrl.Host = "www.52pojie.cn"
	formUrl.RawQuery += "&inajax=1"
	formValue.Set("username", r.Username)
	formValue.Set("password", r.Password)
	formValue.Set("questionid", strconv.Itoa(r.QuestionId))
	formValue.Set("answer", r.Answer)
	formValue.Set("g-recaptcha-response", r.GRecaptchaResponse)
	formValue.Set("cookietime", "7776000")
	{
		// 缺失这一步的话验证码一定会错误
		url := fmt.Sprintf("https://www.52pojie.cn/misc.php?mod=seccode&action=update&idhash=%s&0.551860488365232&modid=undefined", formValue.Get("seccodehash"))
		c.httpClient.Get(url).Do(ctx)
	}
	resp = c.httpClient.Post(formUrl.String()).SetFormDataFromValues(formValue).Do(ctx)
	if resp.Err != nil {
		return kerr.WrapTraceStack(resp.Err)
	}
	if resp.StatusCode != http.StatusOK {
		return kerr.WrapTraceStack(NewErrReq(resp, kerr.New("status code must be 200")))
	}
	/*
		success:
			<?xml version="1.0" encoding="gbk"?>
			<root><![CDATA[<script type="text/javascript" reload="1">if($('succeedmessage')) {$('succeedmessage').innerHTML = '';}if(typeof succeedhandle_=='function') {succeedhandle_('https://www.52pojie.cn/', '', {});}</script><script type="text/javascript">setTimeout("window.location.href ='https://www.52pojie.cn/';", 3000);$('succeedmessage_href').href = 'https://www.52pojie.cn/';$('main_message').style.display = 'none';$('main_succeed').style.display = '';$('succeedlocation').innerHTML = '欢迎您回来，锋芒初露 kaylee595，现在将转入登录前页面';</script>]]></root>
		failed:
			<?xml version="1.0" encoding="gbk"?>
			<root><![CDATA[抱歉，验证码填写错误<script type="text/javascript" reload="1">if(typeof errorhandle_=='function') {errorhandle_('抱歉，验证码填写错误', {});}</script>]]></root>
	*/
	if !regexSucceedLocation.Match(resp.Bytes()) {
		e := &ErrLogin{}
		decoder := xml.NewDecoder(resp.Body)
		decoder.CharsetReader = func(_ string, input io.Reader) (io.Reader, error) { // input已经被req库自动解码了
			return input, nil
		}
		err = decoder.Decode(e)
		if err != nil {
			return kerr.WrapTraceStack(NewErrReq(resp, err))
		}
		e.Msg, _ = htmlString(e.Msg)
		return kerr.WrapTraceStack(e)
	}
	return nil
}
